import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BattleArena {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            GameFrame frame = new GameFrame();
            frame.setVisible(true);
        });
    }
}

class GameFrame extends JFrame {
    private BattlePanel battlePanel;

    public GameFrame() {
        setTitle("Battle Arena - With Cooldowns");
        setSize(800, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        battlePanel = new BattlePanel();
        add(battlePanel);

        JButton startButton = new JButton("Start Battle");
        startButton.addActionListener(e -> battlePanel.startBattle());

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(startButton);
        add(buttonPanel, BorderLayout.SOUTH);
    }
}

class BattlePanel extends JPanel {
    private Fighter player;
    private Fighter enemy;
    private ExecutorService executor;
    private boolean battleOngoing;
    private Lock battleLock;
    private Random random;
    private Map<String, JButton> skillButtons;
    private Map<String, Long> cooldowns;
    private static final long COOLDOWN_TIME = 5000; // 5 seconds in milliseconds

    public BattlePanel() {
        setLayout(new BorderLayout());
        battleLock = new ReentrantLock();
        random = new Random();
        cooldowns = new HashMap<>();
        skillButtons = new HashMap<>();

        // Create fighters
        player = new Fighter("Player", 102, 15, 5, Color.BLUE);
        enemy = new Fighter("Enemy", 132, 25, 15, Color.RED);

        // Set up skill buttons
        JPanel skillPanel = new JPanel();
        String[] skills = {"Basic Attack", "Power Strike", "Defensive Stance", "Heal"};
        for (String skill : skills) {
            JButton skillButton = new JButton(skill);
            skillButton.addActionListener(new SkillListener(skill));
            skillPanel.add(skillButton);
            skillButtons.put(skill, skillButton);
        }
        add(skillPanel, BorderLayout.NORTH);

        executor = Executors.newFixedThreadPool(2);

        // Start cooldown checker thread
        new Thread(() -> {
            while (true) {
                checkCooldowns();
                try {
                    Thread.sleep(100); // Check every 100ms
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }).start();
    }

    private void checkCooldowns() {
        battleLock.lock();
        try {
            long currentTime = System.currentTimeMillis();
            Iterator<Map.Entry<String, Long>> iterator = cooldowns.entrySet().iterator();

            while (iterator.hasNext()) {
                Map.Entry<String, Long> entry = iterator.next();
                String skill = entry.getKey();
                long endTime = entry.getValue();

                if (currentTime >= endTime) {
                    iterator.remove();
                    SwingUtilities.invokeLater(() -> {
                        JButton button = skillButtons.get(skill);
                        if (button != null) {
                            button.setEnabled(true);
                            button.setText(skill);
                        }
                    });
                } else {
                    long remaining = (endTime - currentTime) / 1000 + 1;
                    SwingUtilities.invokeLater(() -> {
                        JButton button = skillButtons.get(skill);
                        if (button != null) {
                            button.setText(skill + " (" + remaining + "s)");
                        }
                    });
                }
            }
        } finally {
            battleLock.unlock();
        }
    }

    private void startCooldown(String skill) {
        battleLock.lock();
        try {
            cooldowns.put(skill, System.currentTimeMillis() + COOLDOWN_TIME);
            skillButtons.get(skill).setEnabled(false);
        } finally {
            battleLock.unlock();
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        // Draw arena
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, getWidth(), getHeight());

        // Draw fighters
        player.draw(g, 150, 250);
        enemy.draw(g, 550, 250);

        // Draw health bars
        drawHealthBar(g, player, 50, 50);
        drawHealthBar(g, enemy, 500, 50);

        // Draw status effects
        drawStatusEffects(g, player, 50, 80);
        drawStatusEffects(g, enemy, 500, 80);
    }

    private void drawHealthBar(Graphics g, Fighter fighter, int x, int y) {
        g.setColor(Color.GRAY);
        g.fillRect(x, y, 200, 20);
        g.setColor(fighter == player ? Color.GREEN : Color.RED);
        int healthWidth = (int)(200 * ((double)fighter.getHealth() / fighter.getMaxHealth()));
        g.fillRect(x, y, healthWidth, 20);
        g.setColor(Color.WHITE);
        g.drawString(fighter.getName() + ": " + fighter.getHealth() + "/" + fighter.getMaxHealth(), x, y + 15);
    }

    private void drawStatusEffects(Graphics g, Fighter fighter, int x, int y) {
        g.setColor(Color.WHITE);
        for (int i = 0; i < fighter.getStatusEffects().size(); i++) {
            StatusEffect effect = fighter.getStatusEffects().get(i);
            g.drawString(effect.toString(), x, y + 20 * (i + 1));
        }
    }

    public void startBattle() {
        if (battleOngoing) return;

        battleOngoing = true;
        player.reset();
        enemy.reset();

        battleLock.lock();
        try {
            cooldowns.clear();
        } finally {
            battleLock.unlock();
        }

        // Enable all buttons
        for (JButton button : skillButtons.values()) {
            button.setEnabled(true);
            button.setText(button.getActionCommand());
        }

        // Start enemy AI thread
        executor.execute(() -> {
            while (battleOngoing && player.isAlive() && enemy.isAlive()) {
                try {
                    Thread.sleep(2000 + random.nextInt(2000)); // Random delay between actions

                    if (!battleOngoing) break;

                    battleLock.lock();
                    try {
                        // Enemy AI logic with cooldowns
                        boolean actionTaken = false;
                        int attempts = 0;

                        while (!actionTaken && attempts < 10) {
                            attempts++;
                            int action = random.nextInt(4);

                            long currentTime = System.currentTimeMillis();
                            boolean canUseSkill = true;
                            String skillName = null;

                            switch (action) {
                                case 0:
                                    skillName = "Basic Attack";
                                    break;
                                case 1:
                                    skillName = "Power Strike";
                                    break;
                                case 2:
                                    skillName = "Defensive Stance";
                                    break;
                                case 3:
                                    skillName = "Heal";
                                    break;
                            }

                            if (skillName != null) {
                                Long cooldownEnd = enemy.getCooldown(skillName);
                                if (cooldownEnd != null && currentTime < cooldownEnd) {
                                    canUseSkill = false;
                                }
                            }

                            if (canUseSkill) {
                                switch (action) {
                                    case 0:
                                        enemy.basicAttack(player);
                                        enemy.startCooldown("Basic Attack");
                                        break;
                                    case 1:
                                        enemy.powerStrike(player);
                                        enemy.startCooldown("Power Strike");
                                        break;
                                    case 2:
                                        enemy.defensiveStance();
                                        enemy.startCooldown("Defensive Stance");
                                        break;
                                    case 3:
                                        enemy.heal();
                                        enemy.startCooldown("Heal");
                                        break;
                                }
                                actionTaken = true;
                            }
                        }

                        repaint();
                        checkBattleEnd();
                    } finally {
                        battleLock.unlock();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        repaint();
    }

    private void checkBattleEnd() {
        if (!player.isAlive()) {
            battleOngoing = false;
            JOptionPane.showMessageDialog(this, "You have been defeated!", "Game Over", JOptionPane.INFORMATION_MESSAGE);
        } else if (!enemy.isAlive()) {
            battleOngoing = false;
            JOptionPane.showMessageDialog(this, "You have defeated the enemy!", "Victory", JOptionPane.INFORMATION_MESSAGE);
        }
    }

    private class SkillListener implements ActionListener {
        private String skillName;

        public SkillListener(String skillName) {
            this.skillName = skillName;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (!battleOngoing || !player.isAlive() || !enemy.isAlive()) return;

            battleLock.lock();
            try {
                // Check cooldown
                long currentTime = System.currentTimeMillis();
                Long cooldownEnd = player.getCooldown(skillName);
                if (cooldownEnd != null && currentTime < cooldownEnd) {
                    return; // Skill is on cooldown
                }

                switch (skillName) {
                    case "Basic Attack":
                        player.basicAttack(enemy);
                        break;
                    case "Power Strike":
                        player.powerStrike(enemy);
                        break;
                    case "Defensive Stance":
                        player.defensiveStance();
                        break;
                    case "Heal":
                        player.heal();
                        break;
                }

                // Start cooldown
                player.startCooldown(skillName);
                startCooldown(skillName);

                repaint();
                checkBattleEnd();
            } finally {
                battleLock.unlock();
            }
        }
    }
}

class Fighter {
    private String name;
    private int health;
    private int maxHealth;
    private int attack;
    private int defense;
    private Color color;
    private java.util.List<StatusEffect> statusEffects;
    private boolean isDefending;
    private Random random;
    private Map<String, Long> cooldowns;
    private Lock cooldownLock;

    public Fighter(String name, int maxHealth, int attack, int defense, Color color) {
        this.name = name;
        this.maxHealth = maxHealth;
        this.health = maxHealth;
        this.attack = attack;
        this.defense = defense;
        this.color = color;
        this.statusEffects = new java.util.ArrayList<>();
        this.random = new Random();
        this.cooldowns = new HashMap<>();
        this.cooldownLock = new ReentrantLock();
    }

    public void basicAttack(Fighter target) {
        int damage = calculateDamage(attack, target);
        target.takeDamage(damage);
        addStatusMessage(name + " used Basic Attack for " + damage + " damage!");
    }

    public void powerStrike(Fighter target) {
        int damage = calculateDamage(attack * 2, target);
        target.takeDamage(damage);
        addStatusMessage(name + " used Power Strike for " + damage + " damage!");

        // 30% chance to stun
        if (random.nextInt(10) < 3) {
            target.addStatusEffect(new StatusEffect("Stunned", 2));
            addStatusMessage(target.name + " was stunned!");
        }
    }

    public void defensiveStance() {
        isDefending = true;
        addStatusEffect(new StatusEffect("Defending", 3));
        addStatusMessage(name + " took a defensive stance!");
    }

    public void heal() {
        int healAmount = maxHealth / 6;
        health = Math.min(maxHealth, health + healAmount);
        addStatusMessage(name + " healed for " + healAmount + " health!");
    }

    public void takeDamage(int amount) {
        if (isDefending) {
            amount = Math.max(1, amount / 2); // Defensive stance reduces damage by half
        }
        health = Math.max(0, health - amount);
    }

    private int calculateDamage(int baseDamage, Fighter target) {
        int damage = baseDamage - target.defense / 2;
        damage = Math.max(1, damage); // Minimum 1 damage
        damage += random.nextInt(3); // Small random variation

        // Check for vulnerability
        if (target.hasStatusEffect("Vulnerable")) {
            damage = (int)(damage * 1.5);
        }

        return damage;
    }

    public void addStatusEffect(StatusEffect effect) {
        // Check if effect already exists
        for (StatusEffect existing : statusEffects) {
            if (existing.getName().equals(effect.getName())) {
                existing.resetDuration(effect.getDuration());
                return;
            }
        }
        statusEffects.add(effect);
    }

    public boolean hasStatusEffect(String effectName) {
        for (StatusEffect effect : statusEffects) {
            if (effect.getName().equals(effectName) && effect.isActive()) {
                return true;
            }
        }
        return false;
    }

    public void updateStatusEffects() {
        statusEffects.removeIf(effect -> !effect.update());
        isDefending = hasStatusEffect("Defending");
    }

    public void draw(Graphics g, int x, int y) {
        g.setColor(color);
        g.fillOval(x, y, 100, 100);
        g.setColor(Color.WHITE);
        g.drawString(name, x + 10, y + 50);
    }

    public void reset() {
        health = maxHealth;
        statusEffects.clear();
        isDefending = false;
        cooldownLock.lock();
        try {
            cooldowns.clear();
        } finally {
            cooldownLock.unlock();
        }
    }

    public boolean isAlive() {
        return health > 0;
    }

    public void startCooldown(String skillName) {
        cooldownLock.lock();
        try {
            cooldowns.put(skillName, System.currentTimeMillis() + 5000); // 5 second cooldown
        } finally {
            cooldownLock.unlock();
        }
    }

    public Long getCooldown(String skillName) {
        cooldownLock.lock();
        try {
            return cooldowns.get(skillName);
        } finally {
            cooldownLock.unlock();
        }
    }

    // Getters
    public String getName() { return name; }
    public int getHealth() { return health; }
    public int getMaxHealth() { return maxHealth; }
    public java.util.List<StatusEffect> getStatusEffects() { return statusEffects; }

    private void addStatusMessage(String message) {
        System.out.println(message); // In a real game, you'd display this in the UI
    }
}

class StatusEffect {
    private String name;
    private int duration;

    public StatusEffect(String name, int duration) {
        this.name = name;
        this.duration = duration;
    }

    public boolean update() {
        duration--;
        return duration > 0;
    }

    public void resetDuration(int newDuration) {
        this.duration = newDuration;
    }

    // Getters
    public String getName() { return name; }
    public int getDuration() { return duration; }
    public boolean isActive() { return duration > 0; }

    @Override
    public String toString() {
        return name + " (" + duration + " turns)";
    }
}